package com.yociyy.sms.validate.code.impl;

import com.yociyy.common.constants.Constants;
import com.yociyy.redis.utils.RedisUtils;
import com.yociyy.sms.exception.ValidateCodeException;
import com.yociyy.sms.validate.code.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

/**
 * 图片验证码处理器抽象类
 *
 * @author: YoCiyy
 * @date: 2020/5/26
 */
public abstract class AbstractValidateCodeProcessor<T extends ValidateCode> implements ValidateCodeProcessor<T> {

	@Autowired
	private Map<String, ValidateCodeGenerator> validateCodeGenerators;

	@Autowired
	private ValidateCodeRepository validateCodeRepository;

	@Autowired
	private RedisUtils redisUtils;

	/**
	 * 创建验证码
	 *
	 * @throws Exception 验证码异常处理
     * @return
	 */
	@Override
	public T create(Map<String, Object> params) throws Exception {
		// 生成验证码
		T validateCode = generate(params);
		// 验证码存入session
		save(params, validateCode);
		// 发送验证码
		send(params, validateCode);
		return validateCode;
	}

	/**
	 * 生成校验码
	 *
	 * @return 验证码信息对象
	 */
	public T generate(Map<String, Object> params) {
		String type = getValidateCodeType(params).toString().toLowerCase();
		String generatorName = type + ValidateCodeGenerator.class.getSimpleName();
		ValidateCodeGenerator validateCodeGenerator = validateCodeGenerators.get(generatorName);
		if (validateCodeGenerator == null) {
			throw new ValidateCodeException("验证码生成器" + generatorName + "不存在");
		}
		return (T) validateCodeGenerator.generate(params);
	}

	/**
	 * 保存验证码至缓存
	 *
	 * @param validateCode 验证码信息对象
	 */
	private void save(Map<String, Object> params, T validateCode) {
		ValidateCode code = new ValidateCode(validateCode.getCode(), validateCode.getExpireTime());
		redisUtils.set(Constants.DEFAULT_CODE_KEY + params.get("randomStr"), code, 60);
	}

	/**
	 * 根据请求的url获取校验码的类型
	 *
	 * @return 验证码类型（短信验证码、图形验证码）
	 */
	private ValidateCodeType getValidateCodeType(Map<String, Object> params) {
		String type = StringUtils.substringBefore(getClass().getSimpleName(), "CodeProcessor");
		return ValidateCodeType.valueOf(type.toUpperCase());
	}

	/**
	 * 验证码校验
	 */
	@Override
	public void validate(Map<String, Object> params) {
		ValidateCodeType validateCodeType = getValidateCodeType(params);

		// 从redis中取出验证码
		T codeInSession = (T) redisUtils.get(Constants.DEFAULT_CODE_KEY + params.get("randomStr"), ValidateCode.class);

		// 从Map中取出验证码
		String validateCode = (String) params.get("code");

		if (StringUtils.isBlank(validateCode)) {
			throw new ValidateCodeException(validateCodeType + "验证码的值不能为空");
		}

		if (codeInSession == null) {
			throw new ValidateCodeException(validateCodeType + "验证码不存在或已过期");
		}

		if (!StringUtils.equals(codeInSession.getCode(), validateCode)) {
			throw new ValidateCodeException(validateCodeType + "验证码不匹配");
		}

		// 移除redis中的验证码
		redisUtils.delete(Constants.DEFAULT_CODE_KEY + params.get("randomStr"));

	}

	/**
	 * 发送校验码，由子类实现
	 *
	 * @param validateCode 验证码信息
	 */
	protected abstract void send(Map<String, Object> params, T validateCode) throws Exception;

}
